/*
 *  hihocoder.com
 *
 *  Category: UNION-FIND
 */

/*-------- Includes --------*/
#include <map>
#include <vector>
#include <iostream>

using namespace std;

/*-------- Defines --------*/


/*-------- Types --------*/


/*-------- Global Variables --------*/
int UF[100002];
int cnt;

/*-------- Function Prototypes --------*/
int find(int k);
void unite(int p, int q);

/*-------- Main Function --------*/
int main(int argc, char const *argv[])
{
    int N;
    int x, y;
    map<int, vector<int>> mpx, mpy;

    // initialize UNION-FIND
    cin >> N;
    for (int i = 0; i < N; ++i) UF[i] = i;
    cnt = N;

    for (int i = 0; i < N; ++i) {
        cin >> x >> y;

        mpx[x].push_back(i);
        mpy[y].push_back(i);
    }

    for (map<int, vector<int>>::iterator it = mpx.begin(); it != mpx.end(); ++it) {
        vector<int> &v = it->second;

        for (int i = 1; i < v.size(); ++i)
            unite(v[i-1], v[i]);
    }

    for (map<int, vector<int>>::iterator it = mpy.begin(); it != mpy.end(); ++it) {
        vector<int> &v = it->second;

        for (int i = 1; i < v.size(); ++i)
            unite(v[i-1], v[i]);
    }

    cout << N - cnt << endl;

    return 0;
}

/*-------- Functions --------*/
int find(int k)
{
    while (k != UF[k]) {
        UF[k] = UF[UF[k]];  // path compress
        k     = UF[k];
    }

    return k;
}

void unite(int p, int q)
{
    int proot = find(p);
    int qroot = find(q);

    if (proot == qroot) return;

    UF[qroot] = proot;
    --cnt;
}
